package YAPserver.gameObjects;

import YAPenvironment.YAPconstant;

/**
 * The Point class is similar to the java.awt.* point2D class.
 * The main difference is that this refers to points as coordinate-vectors.
 * This class is one of two building blocks of all gameObjects. Each gameObject is built of lines and points.
 * @author Daniel
 *
 */

public class Point {
	private double m_xPos;
	private double m_yPos;
	private static String tab = YAPconstant.C_SEPARATOR; 
	
	/**
	 * Constructs a new Point.
	 * @param xPos
	 * @param yPos
	 */
	public Point(double xPos, double yPos){
		this.m_xPos = xPos;
		this.m_yPos = yPos;
	}
	
	/**
	 * Constructs an exact copy of the point in the argument.
	 * @param point point to be copied.
	 */
	public Point(Point point){
		this.m_xPos = point.getXPos();
		this.m_yPos = point.getYPos();
	}
	
	/**
	 * Multiplies the coordinates of this point by a factor k.
	 * @param k double scalar multiplier
	 */
	public void scalarMult(double k){
		this.m_xPos = this.m_xPos*k;
		this.m_yPos = this.m_yPos*k;
	}
	
	/**
	 * Adds the coordinates of another point to this point's coordinates and returns the result as a point.
	 * @param point point to be added
	 * @return a new point which is the sum of two points
	 */
	public Point add(Point point){
		double x = this.getXPos()+point.getXPos();
		double y = this.getYPos()+point.getYPos();
		return new Point(x,y);
	}
	
	/**
	 * Subtracts the coordinates of another point to this point's coordinates and returns the result as a point.
	 * @param point point to be subtracted
	 * @return a new point which is the difference of two points
	 */
	public Point subtract(Point point){
		double x = this.getXPos()-point.getXPos();
		double y = this.getYPos()-point.getYPos();
		return new Point(x,y);
	}
	/**
	 * Calculates the distance between this point and another point.
	 * @param point point to which the distance is calculated
	 * @return the distance between two points
	 */
	public double distance(Point point){
		double x = point.getXPos();
		double y = point.getYPos();
		double distance = Math.sqrt((x-this.m_xPos)*(x-this.m_xPos)+(y-this.m_yPos)*(y-this.m_yPos));
		return distance;
	}
	/**
	 * Calculates the shortest distance between this point and a line.
	 * @param line line to which the distance is calculated
	 * @return the shortest distance between a line and a point
	 */
	public double distance(Line line){
		double x0 = this.getXPos();
		double y0 = this.getYPos();
		double x1 = line.getEndPoint().getXPos();
		double y1 = line.getEndPoint().getYPos();
		double x2 = line.getStartPoint().getXPos();
		double y2 = line.getStartPoint().getYPos();
		
		double distance = Math.abs((x2-x1)*(y1-y0)-(x1-x0)*(y2-y1)) / 
							Math.sqrt((x2-x1)*(x2-x1)+(y2-y1)*(y2-y1));
		return distance;
	}
	
	/**
	 * Very roughly states whether a point is element of a line or not.
	 * It is only valid for points and lines in one dimension.
	 * It is NOT VALID for points and lines in two dimensions.
	 * @param line line to be tested
	 * @return <code>true</code> if is element and <code>false</code> otherwise
	 */
	public boolean isElementOneD(Line line){
		//this gives us the interval for x and y
		Point relPoint = line.getEndPoint().subtract(line.getStartPoint());
		
		//this gives us the relative distance for x and y
		Point distance1 = line.getStartPoint().subtract(this);
		Point distance2 = line.getEndPoint().subtract(this);
		
		//if the xDistance or yDistance is bigger than the x or y distance of the lineEndpoints
		//then return false
		//magic number should be replaced with accuracy
		if(Math.abs(line.getEndPoint().getXPos()-line.getStartPoint().getXPos()) > 5){
			if(Math.abs(distance1.getXPos()) > Math.abs(relPoint.getXPos())){
				return false;
			}
			if(Math.abs(distance2.getXPos()) > Math.abs(relPoint.getXPos())){
				return false;
			}
		}else{
			if(Math.abs(distance1.getYPos()) > Math.abs(relPoint.getYPos())){
				return false;
			}
			if(Math.abs(distance2.getYPos()) > Math.abs(relPoint.getYPos())){
				return false;
			}
		}
		return true;
	}
	
	/**
	 * Calculates precisely whether a point is element of a line or not. Caution that due to the inaccuracy of doubles
	 * this method more often returns false than true.
	 * @param line line to be tested
	 * @return <code>true</code> if is element and <code>false</code> otherwise
	 */
	public boolean isElementTwoD(Line line){
		//this isn't really a line...
		Line point = new Line(this,this);
		if(point.hasIntersection(line)){
			return true;
		}else{
			return false;
		}
	}
	
	/**
	 * Returns true if the points are equal.
	 * @param point point to test if equal
	 * @return <code>true</code> if the points are equal and <code>false</code> otherwise
	 */
	public boolean equals(Point point){
		if(this.getXPos() == point.getXPos() && this.getYPos() == point.getYPos()){
			return true;
		}else{
			return false;
		}
	}
	
	@Override
	//this rounds the x and y positions up and then returns the string
	public String toString(){
		String s="";
		int x = (int) Math.round(this.m_xPos);
		int y = (int) Math.round(this.m_yPos);
		s = s + x + tab + y;
		return s;
	}

	/**
	 * Returns the x coordinate of this point.
	 * @return the x coordinate of this point
	 */
	public double getXPos() {
		return m_xPos;
	}

	/**
	 * Returns the y coordinate of this point.
	 * @return the y coordinate of this point
	 */
	public double getYPos() {
		return m_yPos;
	}

	/**
	 * Sets the x coordinate of this point.
	 * @param xPos new x coordinate
	 */
	public void setXPos(double xPos) {
		this.m_xPos = xPos;
	}

	/**
	 * Sets the y coordinate of this point.
	 * @param yPos new y coordinate
	 */
	public void setYPos(double yPos) {
		this.m_yPos = yPos;
	}
	/**
	 * Sets the x and y coordinates of this point
	 * @param xPos new x coordinate
	 * @param yPos new y coordinate
	 */
	public void setXYPos(double xPos, double yPos){
		this.m_xPos = xPos;
		this.m_yPos = yPos;
	}
}
